別AWSアカウントにあるECRリポジトリへアクセスする方法
しばたです。
あるAWSアカウント内のリソース(EC2など)から別アカウントにあるECRリポジトリに対してアクセスする際は、
- ECRリポジトリのリポジトリポリシー設定
- ECRへアクセスするリソース側の権限設定
を行う必要がありますが、DevelopersIOに私が欲しい感じの解説記事が無かったので自分で書くことにしました。
0. 検証環境
本記事では下図の構成を検証環境として用意しました。
2つのAWSアカウントを用意し、その内一つのアカウント(111111111111
)にECRリポジトリを作成します。
もう一つのアカウント(222222222222
)にDockerをインストールしたEC2インスタンスを用意しECRリポジトリ内のイメージに対してPushとPullを行っていきます。
今回は
- 両アカウントとも東京リージョンを使用
- EC2は本日時点で最新のAmazon Linux 2023環境
- EC2インスタンスからインターネットアクセス可能
という条件で動作確認しています。
1. ECR側設定 (リポジトリポリシー設定)
はじめにAWSアカウント(111111111111
)でECRリポジトリを作成しておきます。
今回はAWS CloudShellからtest-repo
という名前のリポジトリを作成しています。
# Account : 111111111111 でECRリポジトリ作成
aws ecr create-repository --repository-name 'test-repo'
ここから別アカウントからのアクセスを許可するために適切なリポジトリポリシーを設定します。
- 参考 : 例: 別のアカウントを許可する
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowPushPullFromOtherAccount",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::222222222222:root"
},
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload"
]
}
]
}
今回は上記参考ドキュメントに倣ったポリシーを設定しますが、環境や用途に応じてPrincipal
指定や許可するAction
を変更してください。
Principalは許可する相手を指定するのでアカウント(222222222222
)にします。
Actionは基本的に
- Pull用
- ecr:GetDownloadUrlForLayer
- ecr:BatchGetImage
- Push用
- ecr:BatchCheckLayerAvailability
- ecr:PutImage
- ecr:InitiateLayerUpload
- ecr:UploadLayerPart
- ecr:CompleteLayerUpload
を許可すれば事足りると思います。
(足りない場合は適宜追加のActionを許可してください。)
マネジメントコンソールからリポジトリを選択し、アクションの「許可」を選んでリポジトリポリシーの編集画面を開きます。
そして「ポリシーJSONの編集」を選び、
前掲のJSONポリシーを転記して保存します。
設定内容が反映されていればOKです。
2. EC2側設定 (IAMポリシー設定)
次にAWSアカウント(22222222222
)でEC2に適用するIAMポリシー設定を行います。
リポジトリポリシーはリポジトリ側から見たアクセス制御でしたが、こちらのIAMポリシーは「EC2等のアクセス元がどのActionを実行可能か」を指定する形になります。
今回は参考ドキュメントを元に以下の権限を持ったポリシーを作成します。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowAccessToOtherAccountECR",
"Effect": "Allow",
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload"
],
"Resource": "arn:aws:ecr:ap-northeast-1:1111111111:repository/test-repo"
},
{
"Sid": "GetAuthorizationToken",
"Effect": "Allow",
"Action": "ecr:GetAuthorizationToken",
"Resource": "*"
}
]
}
リポジトリポリシーに合わせて次のActionを許可しています。
- Pull用
- ecr:GetDownloadUrlForLayer
- ecr:BatchGetImage
- Push用
- ecr:BatchCheckLayerAvailability
- ecr:PutImage
- ecr:InitiateLayerUpload
- ecr:UploadLayerPart
- ecr:CompleteLayerUpload
これらのActionはリソース指定が可能なためAWSアカウント(111111111111
)のtest-repo
に限定した許可を与えています。
残りの
- AWS認証用
- ecr:GetAuthorizationToken
はリソースを限定することが出来ないため*
指定の許可としています。
ポリシーの作成方法はなんでも構いませんが、今回はマネジメントコンソールからallow-access-to-other-account-ecr-policy
という名前で作成しました。
さらに今回はEC2からアクセスするので、追加でtest-ec2-role
という名前のIAMロールを作成し、allow-access-to-other-account-ecr-policy
ポリシーを割り当てています。
IAMロールの作成手順は割愛します。
3. EC2側設定 (内部設定など)
EC2インスタンス自体はAmazon Linux 2023でt3.small
のインスタンスを作成し、IAMロールtest-ec2-role
を割り当てています。
加えて初期設定として以下の手順でDockerをインストール済みです。
sudo dnf update -y
sudo dnf install -y docker
sudo systemctl start docker
sudo usermod -a -G docker ec2-user
sudo usermod -a -G docker ssm-user
今回はDocker Client 25.0.5, Docker Server 25.0.6がインストールされました。
# インストールしたDockerのバージョンを確認
$ docker version
Client:
Version: 25.0.5
API version: 1.44
Go version: go1.22.5
Git commit: 5dc9bcc
Built: Wed Aug 21 00:00:00 2024
OS/Arch: linux/amd64
Context: default
Server:
Engine:
Version: 25.0.6
API version: 1.44 (minimum version 1.24)
Go version: go1.22.5
Git commit: b08a51f
Built: Wed Aug 21 00:00:00 2024
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.7.22
GitCommit: 7f7fdf5fed64eb6a7caf99b3e12efcf9d60e311c
runc:
Version: 1.1.14
GitCommit: 2c9f5602f0ba3d9da1c2596322dfc4e156844890
docker-init:
Version: 0.19.0
GitCommit: de40ad0
4. 動作確認
ここから実際に動作確認をしていきます。
SSM Sessionを使ってEC2内部にログインし各種コマンドを実行します。
4-1. リポジトリへのPush
はじめにtest-repo
リポジトリに対して適当なDockerイメージをPushします。
前準備として適当なDockerfile
からDockerイメージを作成します。
Dockerfile
は単体でビルド可能なものであればなんでも良いのですが、今回は私個人のGitHubリポジトリにある以下のDockerfile
[1]を使うことにします。
curlコマンド等でDockerfile
をダウンロードしておき、
# 動作確認用Dockerfileをダウンロード
curl -O https://raw.githubusercontent.com/stknohg/aws-cli-eq-pwsh/refs/heads/main/Dockerfile
docker build
コマンドでイメージを作成、ECRへのPush用にタグ付けまで行っておきます。
ここは一般的なECRへのPush方法と同じです。
# Dockerイメージ作成 + タグ付け
docker build -t test-repo .
docker tag test-repo:latest 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo:latest
結果はこんな感じです。
# 作成されたイメージを確認
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo latest 0f196693ce1c 33 seconds ago 1.45GB
test-repo latest 0f196693ce1c 33 seconds ago 1.45GB
続けてこのイメージをECRリポジトリにPushします。
docker login
とdocker push
コマンドの組み合わせ自体は通常のECRへのPushと同じですが、リポジトリ指定が別アカウント(111111111111
)になります。
# ECRへのPush
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com
docker push 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo:latest
ポリシー設定等に問題がなければエラー無くPushされ、次の様な結果になります。
$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com
WARNING! Your password will be stored unencrypted in /home/ssm-user/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
$ docker push 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo:latest
The push refers to repository [111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo]
3675938c6474: Pushed
eed3f3c893c9: Pushed
7d42b235083d: Pushed
41ee9381f1ba: Pushed
1b9b7346fee7: Pushed
latest: digest: sha256:1f1d9c0668b54bd4f4aab272ff9599dd9056ebd23ffc29782dd9b5f07f9fef1b size: 1379
マネジメントコンソールからECRリポジトリを確認するとちゃんとイメージが保存されていました。
4-2. リポジトリからのPull
次にこのイメージをPullしていきます。
動作確認のため、一旦ローカルにあるDockerイメージを全て削除してキャッシュもクリアしておきます。
# 既存イメージの削除とキャッシュのクリア
docker images -q | xargs docker rmi -f {}
docker system prune --volumes -f
# 保存された認証情報も削除
rm /home/ssm-user/.docker/config.json
docker images
コマンドでイメージが無くなっていることを確認しておきます。
# ローカルにイメージが無い状態に
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
この状態でECRリポジトリからイメージをPullします。
# ECRからPullする
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com
docker pull 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo:latest
こちらもポリシー設定等に問題がなければエラー無くPullされて以下の様になります。[2]
$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com
WARNING! Your password will be stored unencrypted in /home/ssm-user/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
$ docker pull 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo:latest
latest: Pulling from test-repo762bedf4b1b7: Already exists
57ed3936f2b8: Already exists
8889f02ed290: Already exists
e4cc63e7c8d3: Already exists
fdba7b911ffb: Already exists
Digest: sha256:1f1d9c0668b54bd4f4aab272ff9599dd9056ebd23ffc29782dd9b5f07f9fef1b
Status: Downloaded newer image for 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo:latest
111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo:latest
最後にdocker images
コマンドでイメージがあることを確認しておきます。
# Pullした結果を確認
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo latest 0f196693ce1c 23 minutes ago 1.45GB
最後に
以上となります。
今回はEC2からのアクセスを試しましたが、他リソースからアクセスする場合においても基本的な部分は変わらないので参考になると思います。
本記事の内容が皆さんの役に立てば幸いです。